﻿// The Nova Project by Ken Beckett.
// Copyright (C) 2007-2012 Inevitable Software, all rights reserved.
// Released under the Common Development and Distribution License, CDDL-1.0: http://opensource.org/licenses/cddl1.php

using System.Collections.Generic;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;

using Nova.CodeDOM;

namespace Nova.UI
{
    /// <summary>
    /// The view model for a <see cref="CodeDOM.While"/>.
    /// </summary>
    public class WhileVM : BlockStatementVM
    {
        #region /* STATICS */

        internal static void AddViewModelMapping()
        {
            CreateViewModel.Add(typeof(While),
                delegate(CodeObject codeObject, bool isDescription, Dictionary<CodeObject, CodeObjectVM> dictionary) { return new WhileVM((While)codeObject, isDescription, dictionary); });
        }

        #endregion

        #region /* FIELDS */

        protected ExpressionVM _conditionalVM;
        protected DoWhileVM _doWhileVM;

        #endregion

        #region /* CONSTRUCTORS */

        /// <summary>
        /// Create a view model instance for the specified <see cref="CodeDOM.While"/>.
        /// </summary>
        public WhileVM(While @while, bool isDescription, Dictionary<CodeObject, CodeObjectVM> dictionary)
            : base(@while, isDescription, dictionary)
        {
            _conditionalVM = (ExpressionVM)CreateVM(@while.Conditional, isDescription, dictionary);
            _doWhileVM = (DoWhileVM)CreateVM(@while.DoWhile, isDescription, dictionary);
        }

        #endregion

        #region /* PROPERTIES */

        /// <summary>
        /// The underlying <see cref="CodeDOM.While"/> model.
        /// </summary>
        public While While
        {
            get { return (While)CodeObject; }
        }

        /// <summary>
        /// The conditional <see cref="ExpressionVM"/>.
        /// </summary>
        public ExpressionVM ConditionalVM
        {
            get { return _conditionalVM; }
        }

        /// <summary>
        /// True if there is a conditional <see cref="CodeDOM.Expression"/>.
        /// </summary>
        public bool HasConditionVM
        {
            get { return (_conditionalVM != null); }
        }

        /// <summary>
        /// The <see cref="DoWhileVM"/> part if this is a 'do/while' loop.
        /// </summary>
        public DoWhileVM DoWhileVM
        {
            get { return _doWhileVM; }
        }

        /// <summary>
        /// True if this is a 'do/while' loop.
        /// </summary>
        public bool IsDoWhile
        {
            get { return While.IsDoWhile; }
        }

        #endregion

        #region /* METHODS */

        #endregion

        #region /* RENDERING */

        public override Brush BorderBrush
        {
            get { return DarkLavender; }
        }

        public override Brush BackgroundBrush
        {
            get { return Brushes.Lavender; }
        }

        /// <summary>
        /// Determines if a 'while' with a null condition should be rendered as 'do'.
        /// </summary>
        public static bool DisplayAsDoIfNullCondition;

        protected override void RenderStatement(CodeRenderer renderer, RenderFlags flags)
        {
            renderer.RenderText((IsDoWhile || (!HasConditionVM && DisplayAsDoIfNullCondition)) ? While.ParseTokenDo : While.ParseToken, KEYWORD_BRUSH, this);
            if (!HasConditionVM && !DisplayAsDoIfNullCondition)
            {
                // Render a null condition as "while (true)" if the 'do' option isn't on
                RenderFlags passFlags = (flags & RenderFlags.PassMask);
                RenderArgumentPrefix(renderer, passFlags);
                bool showParens = Statement.HasArgumentParens && RenderParens();
                if (showParens)
                    renderer.RenderText(CodeDOM.Expression.ParseTokenStartGroup, PUNC_BRUSH, this);
                Literal literal = new Literal(true);
                CreateVM(literal, this).Render(renderer, passFlags | RenderFlags.ForceBorder);
                if (showParens)
                {
                    if (Statement.IsEndFirstOnLine)
                        renderer.NewLine();
                    renderer.RenderText(CodeDOM.Expression.ParseTokenEndGroup, PUNC_BRUSH, this);
                }
            }
        }

        protected override void RenderArgument(CodeRenderer renderer, RenderFlags flags)
        {
            if (_conditionalVM != null)
                _conditionalVM.Render(renderer, flags);
        }

        protected override void RenderAfter(CodeRenderer renderer, RenderFlags flags)
        {
            base.RenderAfter(renderer, flags);
            if (IsDoWhile)
                _doWhileVM.Render(renderer, flags | RenderFlags.PrefixSpace);
        }

        public override void RenderVisible(CodeRenderer renderer, RenderFlags flags)
        {
            base.RenderVisible(renderer, flags);
            if (_conditionalVM != null)
                _conditionalVM.RenderVisible(renderer, flags);
            if (_doWhileVM != null)
                _doWhileVM.RenderVisible(renderer, flags);
        }

        public override void UnRender()
        {
            if (_conditionalVM != null)
                _conditionalVM.UnRender();
            if (_doWhileVM != null)
                _doWhileVM.UnRender();
            base.UnRender();
        }

        #endregion

        #region /* COMMANDS */

        public static readonly RoutedCommand DisplayAsDoIfNullConditionCommand = new RoutedCommand("Display While as Do if Null Condition", typeof(WhileVM));

        public static new void BindCommands(Window window)
        {
            WPFUtil.AddCommandBinding(window, DisplayAsDoIfNullConditionCommand, displayAsDoIfNullCondition_Executed);
        }

        private static void displayAsDoIfNullCondition_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            DisplayAsDoIfNullCondition = !DisplayAsDoIfNullCondition;
            CodeRenderer.ReRenderAll();
        }

        #endregion
    }
}
